#ifndef PSFTrajectory_h
#define PSFTrajectory_h 1

#include "globals.hh"
#include "G4Allocator.hh"
#include "G4ParticleDefinition.hh"
#include "G4Step.hh"
#include "G4Track.hh"
#include "G4TrajectoryPoint.hh"
#include "G4VTrajectory.hh"

#include <vector>

typedef std::vector<G4VTrajectoryPoint *> PSFTrajectoryPointContainer;

class PSFTrajectory : public G4VTrajectory
{
public:
  PSFTrajectory() = default;
  PSFTrajectory(const G4Track *);
  PSFTrajectory(PSFTrajectory &);
  ~PSFTrajectory() override;

  inline void *operator new(size_t);
  inline void operator delete(void *);
  inline int operator==(const PSFTrajectory &right) const
  {
    return (this == &right);
  }

  inline G4int GetTrackID() const override { return fTrackID; }
  inline G4int GetParentID() const override { return fParentID; }
  inline G4String GetParticleName() const override { return fParticleName; }
  inline G4double GetCharge() const override { return fPDGCharge; }
  inline G4int GetPDGEncoding() const override { return fPDGEncoding; }
  inline G4ThreeVector GetInitialMomentum() const override
  {
    return fInitialMomentum;
  }

  void ShowTrajectory(std::ostream &os = G4cout) const override;
  void AppendStep(const G4Step *aStep) override;
  void MergeTrajectory(G4VTrajectory *secondTrajectory) override;

  G4ParticleDefinition *GetParticleDefinition();

  int GetPointEntries() const override { return fpPointsContainer->size(); }
  G4VTrajectoryPoint *GetPoint(G4int i) const override
  {
    return (*fpPointsContainer)[i];
  }

  const std::map<G4String, G4AttDef> *GetAttDefs() const override;
  std::vector<G4AttValue> *CreateAttValues() const override;

private:
  PSFTrajectoryPointContainer *fpPointsContainer = nullptr;

  G4int fTrackID = 0;
  G4int fParentID = 0;
  G4double fPDGCharge = 0.;
  G4int fPDGEncoding = 0;
  G4String fParticleName;
  G4ThreeVector fInitialMomentum;

  G4ParticleDefinition *fParticleDefinition = nullptr;
};

extern G4ThreadLocal G4Allocator<PSFTrajectory> *PSFTrajectoryAllocator;

inline void *PSFTrajectory::operator new(size_t)
{
  if (!PSFTrajectoryAllocator)
    PSFTrajectoryAllocator = new G4Allocator<PSFTrajectory>;
  return (void *)PSFTrajectoryAllocator->MallocSingle();
}

inline void PSFTrajectory::operator delete(void *aTrajectory)
{
  PSFTrajectoryAllocator->FreeSingle((PSFTrajectory *)aTrajectory);
}

#endif
